home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / audio / DAT / cdtodat.c next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  20.4 KB  |  713 lines

  1. /*
  2.  * A simple program to transfer CD data to DAT
  3.  *
  4.  * Doug Cook
  5.  * Silicon Graphics, Inc., December 1993
  6.  *
  7.  * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
  8.  * ALL RIGHTS RESERVED
  9.  * Permission to use, copy, modify, and distribute this software for
  10.  * any purpose and without fee is hereby granted, provided that the above
  11.  * copyright notice appear in all copies and that both the copyright notice
  12.  * and this permission notice appear in supporting documentation, and that
  13.  * the name of Silicon Graphics, Inc. not be used in advertising
  14.  * or publicity pertaining to distribution of the software without specific,
  15.  * written prior permission.
  16.  *
  17.  * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
  18.  * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
  19.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
  20.  * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
  21.  * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
  22.  * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
  23.  * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
  24.  * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
  25.  * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
  26.  * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
  27.  * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
  28.  * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
  29.  *
  30.  * US Government Users Restricted Rights
  31.  * Use, duplication, or disclosure by the Government is subject to
  32.  * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
  33.  * (c)(1)(ii) of the Rights in Technical Data and Computer Software
  34.  * clause at DFARS 252.227-7013 and/or in similar or successor
  35.  * clauses in the FAR or the DOD or NASA FAR Supplement.
  36.  * Unpublished-- rights reserved under the copyright laws of the
  37.  * United States.  Contractor/manufacturer is Silicon Graphics,
  38.  * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
  39.  *
  40.  */
  41.  
  42.  
  43. #include <sys/types.h>
  44. #include <sys/errno.h>
  45. #include <sys/tpsc.h>
  46. #include <sys/mtio.h>
  47. #include <sys/prctl.h>
  48. #include <fcntl.h>
  49. #include <cdaudio.h>
  50. #include <dataudio.h>
  51. #include <stdio.h>
  52. #include <audio.h>
  53.  
  54. /*
  55.  * #define AUDIO if you want to play the CD to the audio system
  56.  * instead of writing to DAT. 
  57.  */
  58.  
  59. #define NFRAMES 12
  60.  
  61. #define QUEUESIZE 68
  62. #define HIGHWATER 34
  63.  
  64. static char *datdev = "/dev/nrtape";
  65.  
  66. static int verbose = 1;
  67.  
  68. static int startidframes;    /* # of frames left in DAT track start ID */
  69.  
  70. /*
  71.  * we define a word-aligned DAT frame. Writes directly to a scsi
  72.  * device can only come from word-aligned addresses. If we made an
  73.  * array of regular DAT frames, every other one would not be word-aligned.
  74.  */
  75. typedef struct wadtframe {        /* word-aligned DAT frame */
  76.     DTFRAME frame;
  77.     short pad;
  78. } WADTFRAME;
  79.  
  80.  
  81. /*
  82.  * We implement a circular queue of DAT audio frames. One process 
  83.  * reads from the CD and writes data to the queue in DAT format.
  84.  * when the size of the queue hits a high-water mark, another process
  85.  * wakes up and begins to write data to the DAT from the other end
  86.  * of the queue. This extra buffering is required because both CD and
  87.  * DAT run at "exactly" 44.1kHz, but off of different clocks. They
  88.  * may therefore generate or consume data at slightly different rates.
  89.  */
  90.  
  91. static WADTFRAME dtq[QUEUESIZE];    /* queue of DAT audio frames */
  92. static volatile int head = 0, tail = 0;    /* queue head & tail pointers */
  93. static volatile int finish = 0;
  94.  
  95. /*
  96.  * dtf is the "template" DAT frame. It is modified continually by the
  97.  * process reading the CD, then copied into the queue. This prevents
  98.  * us from having to update all the DAT fields all the time; we just
  99.  * update those fields which change from frame to frame.
  100.  */
  101. static DTFRAME dtf;            
  102. static int dtf_nsamps=0;    /* number of audio samps currently in dtf */
  103. static DTFRAME empty;
  104. static index;             /* current index being recorded */
  105.  
  106. void
  107. cd_control_func(void *arg, CDDATATYPES type, unsigned char *flags)
  108. {
  109.     /*
  110.      * Determine whether or not copy protect is enabled
  111.      * on the CD. If so, we must pass it through to the
  112.      * DAT.
  113.      */
  114.     dtf.subcode.mid.copy = 
  115.         ((*flags & CDQ_COPY_MASK) == CDQ_COPY_PERMITTED) ?
  116.          DTM_COPY_PERMITTED : DTM_COPY_PROHIBITED;
  117. }
  118.  
  119. void
  120. cd_index_func(void *arg, CDDATATYPES type, CDPROGNUM *inum)
  121. {
  122.     struct dttimepack *tpp;
  123.     struct dttimecode *tcp;
  124.  
  125.     index = inum->value;
  126.  
  127.     if (verbose) {
  128.         printf("index %d\n",index);
  129.     }
  130.  
  131.     /*
  132.      * set up the subcode bits
  133.      */
  134.     tpp = (struct dttimepack *)&dtf.subcode.packs[DTP_ATIME-1];
  135.     tpp->index.dhi = index / 10;
  136.     tpp->index.dlo = index % 10;
  137.     tpp = (struct dttimepack *)&dtf.subcode.packs[DTP_PTIME-1];
  138.     tcp = &tpp->tc;
  139.     tpp->index.dhi = index / 10;
  140.     tpp->index.dlo = index % 10;
  141.     if (index == 0) {
  142.     /* 
  143.      * The DAT spec states that when index=0, times stay 
  144.      * at 0.
  145.      */
  146.     bzero(tcp,sizeof(struct dttimecode));
  147.     }
  148.     /* ...and we don't bother with r-time */
  149. }
  150.  
  151. void
  152. cd_pnum_func(void *arg, CDDATATYPES type, CDPROGNUM *pnum)
  153. {
  154.     int p = pnum->value;
  155.     struct dttimepack *tpp;
  156.     struct dttimecode *tcp;
  157.  
  158.     if (verbose) {
  159.         printf("program %d\n",p);
  160.     }
  161.     /*
  162.      * set up the subcode bits
  163.      */
  164.     tpp = (struct dttimepack *)&dtf.subcode.packs[DTP_ATIME-1];
  165.  
  166.     /* don't write pno1 because CD progs only go up to 99 */
  167.     tpp->pno2 = dtf.subcode.sid.pno2 = p / 10;
  168.     tpp->pno3 = dtf.subcode.sid.pno3 = p % 10;
  169.     tpp = (struct dttimepack *)&dtf.subcode.packs[DTP_PTIME-1];
  170.     tpp->pno2 = dtf.subcode.sid.pno2;
  171.     tpp->pno3 = dtf.subcode.sid.pno3;
  172.     /* ...and we don't bother with r-time */
  173.  
  174.     tcp = &tpp->tc;
  175.  
  176.     /* don't bother writing hours since they're always 0 */
  177.     tcp->mhi = 0;
  178.     tcp->mlo = 0;
  179.     tcp->shi = 0;
  180.     tcp->slo = 0;
  181.     tcp->fhi = 0;
  182.     tcp->flo = 0;
  183.  
  184.     /*
  185.      * now we set it up so that the next 300 frames
  186.      * have the start id bit set, indicating start-of-program.
  187.      * DAT spec sez START must be set for 300 frames at start-of-program
  188.      * and PRIORITYID must be set whenever program # is valid.
  189.      */
  190.     dtf.subcode.sid.ctrlid |= (DTS_PRIORITYID | DTS_START);
  191.     startidframes = 300;
  192. }
  193.  
  194. void
  195. write_DAT(void *fd)
  196. {
  197.     int filled;
  198.     struct dttimepack *tpp;
  199.     struct dttimecode *tcp;
  200. #ifdef AUDIO
  201.     static ALport p = 0;
  202.     ALconfig c;
  203. #endif
  204.  
  205.     do {
  206.         filled = tail - head;
  207.         if (filled < 0) {
  208.             filled += QUEUESIZE; 
  209.         }
  210.     } while (filled < HIGHWATER);
  211.  
  212.     while (1) {
  213.         while (tail == head) {
  214.             if (finish) return;
  215.         }
  216. #ifndef AUDIO
  217.         if (write((int)fd,&(dtq[head].frame),sizeof(DTFRAME)) < 0) {
  218.             perror("DAT write failed");
  219.             exit(-1);
  220.         }
  221. #endif
  222.  
  223. #ifdef AUDIO
  224.         if (!p) {
  225.              c = ALnewconfig();
  226.             ALsetqueuesize(c,DTDA_NUMSAMPS44K*2);
  227.             p = ALopenport("CDtest","w",c);
  228.             ALfreeconfig(c);
  229.         }
  230.         ALwritesamps(p, &dtq[head].frame.audio, DTDA_NUMSAMPS44K);
  231. #endif
  232.     /* we increment head carefully so it only takes 1 write to do so */
  233.         if (head == QUEUESIZE-1) {
  234.         head = 0;
  235.     }
  236.     else {
  237.         head++;
  238.     }
  239.     }
  240. }
  241.  
  242. void
  243. fix_parity()
  244. {
  245.     volatile unchar *pp;
  246.     int i;
  247.  
  248.     /*
  249.      * calculate the parity bytes for the packs we are using.
  250.      */
  251.     for(i = 0; i<dtf.subcode.sid.numpacks; i++) {
  252.         pp = (volatile unchar *)&dtf.subcode.packs[i];
  253.         dtf.subcode.packs[i].parity
  254.             = pp[0] ^ pp[1] ^ pp[2] ^ pp[3] ^ pp[4] ^ pp[5] ^ pp[6];
  255.     }
  256. }
  257.  
  258. void
  259. adjust_time()
  260. {
  261.     struct dttimepack *tpp;
  262.     struct dttimecode *tcp;
  263.  
  264.     /*
  265.      * increment Atime normally.
  266.      */
  267.     tpp = (struct dttimepack *)&dtf.subcode.packs[DTP_ATIME-1];
  268.     tcp = &tpp->tc;
  269.     DTinctime(tcp);
  270.  
  271.     /* 
  272.      * The DAT spec states that when index=0, ptime stays
  273.      * at 0. Otherwise, we increment the ptime.
  274.      */
  275.     if (index != 0) {
  276.         tpp = (struct dttimepack *)&dtf.subcode.packs[DTP_PTIME-1];
  277.         tcp = &tpp->tc;
  278.         DTinctime(tcp);
  279.     }
  280.  
  281.     if (startidframes > 0) {  
  282.         startidframes--;
  283.         if(startidframes==0) {
  284.             /* shut off start ID bit after startidframes */
  285.             dtf.subcode.sid.ctrlid  &= ~DTS_START;
  286.         }
  287.     }
  288. }
  289.  
  290. void
  291. swapcopy(ushort *a, ushort *b, int n)
  292. {
  293.     ushort *done = a + n;
  294.     while(a != done) {
  295. #ifndef AUDIO
  296.     /* DAT audio frames must have the audio byte-swapped */
  297.         *b++ = ((*a & 0xff) << 8)+(*a >> 8);
  298. #else
  299.     /* AL audio frames do not byte-swap the audio */
  300.         *b++ = *a;
  301. #endif
  302.         a++;
  303.     }
  304. }
  305.  
  306. void
  307. cd_audio_func(void *arg, CDDATATYPES type, short *audio)
  308. {
  309.     int filled;
  310.     int qfull = 0;
  311.  
  312.     /*
  313.      * The size of a CD frame and the size of a DAT frame vastly differ.
  314.      * The DAT frames are much larger. We have to accumulate enough CD
  315.      * frames to fill a DAT frame before we can stick the DAT frame on
  316.      * the queue to be written. There are two cases: (1) the CD frame
  317.      * fills the DAT frame, in which case it must be split into two
  318.      * pieces, the full DAT frame shoved onto the queue, and the remaining
  319.      * piece used to partially fill the next DAT frame; and (2) the entire CD 
  320.      * frame fits into the DAT frame, in which case we just stick it in.
  321.      */
  322.     if (dtf_nsamps + CDDA_NUMSAMPLES >= DTDA_NUMSAMPS44K) {
  323.     /* 
  324.      * case 1: we must split the CD frame and write the DAT frame
  325.      * s is the split point.
  326.      */
  327.         int s = DTDA_NUMSAMPS44K - dtf_nsamps;        
  328.         swapcopy((ushort*)audio,((ushort *)&dtf.audio)+dtf_nsamps, s);
  329.  
  330.         /* if queue is full, wait until space is available */
  331.         do {
  332.             filled = tail - head;
  333.             if (filled < 0) {
  334.                 filled += QUEUESIZE; 
  335.             }
  336.     
  337.             if (filled == QUEUESIZE - 1 && qfull==0) {
  338.                 printf("queue is full! DAT may have glitches.\n");
  339.         qfull = 1;
  340.         }
  341.  
  342.         } while (filled >= QUEUESIZE - 1);
  343.     qfull = 0;
  344.  
  345.     /*
  346.      * calculate the parity in the subcode packs, write the DAT
  347.      * frame to the queue, and adjust the times in the subcode packs.
  348.      */
  349.         fix_parity();        
  350.         bcopy(&dtf,&dtq[tail].frame,sizeof(DTFRAME));    
  351.         adjust_time();    
  352.  
  353.     /* we increment tail carefully so it only takes 1 write to do so */
  354.         if (tail == QUEUESIZE-1) {
  355.         tail = 0;
  356.     }
  357.     else {
  358.         tail++;
  359.     }
  360.  
  361.         swapcopy((ushort *)audio+s, (ushort *)&dtf.audio, (CDDA_NUMSAMPLES-s));
  362.         dtf_nsamps = CDDA_NUMSAMPLES-s;
  363.     }
  364.     else {
  365.     /* 
  366.      * case 2: the CD frame fits in the DAT frame
  367.      */
  368.         swapcopy((ushort *)audio,((ushort *)&dtf.audio)+dtf_nsamps, CDDA_NUMSAMPLES);
  369.         dtf_nsamps += CDDA_NUMSAMPLES;
  370.     }
  371. }
  372.  
  373. int 
  374. get_firmware_revision(int fd, int *maj, int *min)
  375. {
  376.     ct_g0inq_data_t info;
  377.     char revbuf1[MAX_INQ_PRL + 1];
  378.  
  379.     if (ioctl(fd, MTSCSIINQ, &info) >= 0) {
  380.         strncpy(revbuf1, (char *)info.id_prl, MAX_INQ_PRL);
  381.         *maj = atoi(strtok(revbuf1, "."));
  382.         *min = atoi(strtok(NULL, "."));
  383.         return 0;
  384.     }
  385.     else {
  386.         return -1;     /*ioctl failed */
  387.     }
  388. }
  389.  
  390. int
  391. finish_dat(int fd)
  392. {
  393.     int i;
  394.     struct dttimepack *tpp;
  395.  
  396.     /*
  397.      * use the same dummy frame we used to write the leader,
  398.      * except switch from lead-in to lead-out subcodes.
  399.      */
  400.     empty.subcode.sid.pno1 = 0;
  401.     empty.subcode.sid.pno2 = empty.subcode.sid.pno3 = 0xE;   /* EOT */
  402.     empty.subcode.sid.ctrlid =  DTS_START;
  403.     tpp = (struct dttimepack *)&empty.subcode.packs[DTP_ATIME-1];
  404.     tpp->pno2 = tpp->pno3 = 0xE;   /* EOT */
  405.     tpp = (struct dttimepack *)&empty.subcode.packs[DTP_PTIME-1];
  406.     tpp->pno2 = tpp->pno3 = 0xE;   /* EOT */
  407.     tpp = (struct dttimepack *)&empty.subcode.packs[DTP_RTIME-1];
  408.     tpp->pno2 = tpp->pno3 = 0xE;   /* EOT */
  409.  
  410.     /*
  411.      * Write this dummy frame to the tape to make the trailer
  412.      * DAT spec sez lead-out must be >=300 frames
  413.      */
  414.     for (i = 0; i < 300; i++) {
  415.         if ((write(fd, &empty, sizeof(DTFRAME))) < 0) {
  416.             perror("tape write failed on trailer");
  417.             return 0;
  418.         }
  419.     }
  420. }
  421.  
  422. int
  423. prepare_dat(int fd)
  424. {
  425.     int i;
  426.     struct mtop mtc;
  427.     struct mtaudio mta;
  428.     struct mtget mtg;
  429.     struct dttimecode *tcp;
  430.     struct dttimepack *tpp;
  431.     struct dttimepack *tpp1;
  432.  
  433.     /*
  434.      * Put the DAT drive in audio mode. 
  435.      */
  436.     mtc.mt_op = MTAUD;
  437.     mtc.mt_count = 1;
  438.     if (ioctl(fd, MTIOCTOP, &mtc) < 0) {
  439.         if (oserror() != EAGAIN) {
  440.             perror("Couldn't put DAT into audio mode");
  441.             return(0);
  442.         }
  443.     }
  444.      
  445.     /*
  446.      * Now get some information about the DAT media
  447.      * We'll use this momentarily.
  448.      */
  449.     if (ioctl(fd, MTIOCGET, &mtg) < 0) {
  450.         perror("Couldn't issue MTIOCGET");
  451.         return(0);
  452.     }
  453.  
  454.     /*
  455.      * rewind the tape.
  456.      * Note that a rewind does not block. The rewind goes on while
  457.      * the program continues. The first write will block until
  458.      * the rewind completes. 
  459.      * We want the drive in audio mode here because BOT is different
  460.      * between data and audio modes (data mode rewinds to logical
  461.      * BOT, which is a little ways into the tape, and we want real
  462.      * BOT). 
  463.      */
  464.     if ((mtg.mt_erreg & (CT_AUD_MED >> 16)) == 0 && 
  465.         (mtg.mt_dsreg & CT_BOT)) {
  466.         /*
  467.          * firmware bug workaround. Tapes which have previously 
  468.          * been written with non-audio data are considered "data
  469.          * tapes." Their format differs from that of audio tapes. 
  470.          * If the tape in the drive  is considered a data tape, and
  471.          * the drive thinks it's at BOT, we want to move it off 
  472.          * BOT so that the drive will really rewind it when we issue  
  473.          * MTREW. Can't do a read, since a read of a data tape in 
  474.          * audio mode will fail. The write will force the medium to  
  475.          * become an audio tape.
  476.          */
  477.     if (verbose)
  478.             printf("fixing a data tape at BOT to be an audio tape at BOT\n");
  479.         write(fd,&empty,sizeof(DTFRAME));
  480.     }
  481.     mtc.mt_op = MTREW;
  482.     mtc.mt_count = 1;
  483.     ioctl(fd, MTIOCTOP, &mtc);
  484.  
  485.     /*
  486.      * The previous rewind operation is asynchronous. We don't wait for
  487.      * it, however, because the next read or write will block waiting for
  488.      * it to complete.
  489.      */
  490.  
  491.     /*
  492.      * Now we stick some "lead-in" area on the start
  493.      * of the tape. 
  494.      */
  495.     bzero(&empty, sizeof(DTFRAME));
  496.     empty.subcode.sid.pno1 = 0;
  497.     empty.subcode.sid.pno2 = empty.subcode.sid.pno3 = 0xB;   /* BOT */
  498.     empty.subcode.sid.ctrlid =  DTS_START;
  499.  
  500.     /*
  501.      * Write all timecode packs, and indicate values in
  502.      * all are invalid (but present!)
  503.      */
  504.     empty.subcode.mid.sampfreq = DT_FREQ44100;
  505.     empty.subcode.packs[DTP_ATIME-1].id = DTP_ATIME;
  506.     empty.subcode.packs[DTP_PTIME-1].id = DTP_PTIME;
  507.     empty.subcode.packs[DTP_RTIME-1].id = DTP_RTIME;
  508.     tpp = (struct dttimepack *)&empty.subcode.packs[DTP_ATIME-1];
  509.     tcp = &tpp->tc;
  510.     tpp->pno1 = 0;
  511.     tpp->pno2 = tpp->pno3 = 0xB;   /* BOT */
  512.     tcp->hhi = tcp->hlo = tcp->mhi = tcp->mlo = tcp->shi = 
  513.     tcp->slo = tcp->fhi = tcp->flo = 0xA;
  514.     tpp = (struct dttimepack *)&empty.subcode.packs[DTP_PTIME-1];
  515.     tcp = &tpp->tc;
  516.     tcp->hhi = tcp->hlo = tcp->mhi = tcp->mlo = tcp->shi = 
  517.     tcp->slo = tcp->fhi = tcp->flo = 0xA;
  518.     tpp->pno1 = 0;
  519.     tpp->pno2 = tpp->pno3 = 0xB;   /* BOT */
  520.     tpp = (struct dttimepack *)&empty.subcode.packs[DTP_RTIME-1];
  521.     tcp = &tpp->tc;
  522.     tcp->hhi = tcp->hlo = tcp->mhi = tcp->mlo = tcp->shi = 
  523.     tcp->slo = tcp->fhi = tcp->flo = 0xA;
  524.     tpp->pno1 = 0;
  525.     tpp->pno2 = tpp->pno3 = 0xB;   /* BOT */
  526.     empty.subcode.sid.numpacks = 3;
  527.  
  528.     /*
  529.      * Write this dummy frame to the tape to make the leader
  530.      * (i've always wondered how dummies became leaders...)
  531.      */
  532.     for (i = 0; i < 100; i++) {
  533.         if ((write(fd, &empty, sizeof(DTFRAME))) < 0) {
  534.             perror("tape write failed on leader");
  535.             return 0;
  536.         }
  537.     }
  538.  
  539.     /*
  540.      * initialize a dat frame
  541.      */ 
  542.     bzero(&dtf,sizeof(DTFRAME));
  543.  
  544.     /*
  545.      * set up the rate bits
  546.      */
  547.     dtf.subcode.mid.sampfreq = DT_FREQ44100;
  548.  
  549.     /*
  550.      * set up the subcode bits
  551.      */
  552.     tpp = (struct dttimepack *)&dtf.subcode.packs[DTP_ATIME-1];
  553.     tpp->id = DTP_ATIME;
  554.  
  555.     tpp->index.dhi = 0;
  556.     tpp->index.dlo = 1;
  557.     tpp->pno1 = dtf.subcode.sid.pno1 = 0;
  558.     tpp->pno2 = dtf.subcode.sid.pno2 = 0;
  559.     tpp->pno3 = dtf.subcode.sid.pno3 = 1;
  560.     tpp1 = (struct dttimepack *)&dtf.subcode.packs[DTP_PTIME-1];
  561.     *tpp1 = *tpp;
  562.     tpp1->id = DTP_PTIME;
  563.  
  564.     /* mark R-time as invalid, since we don't really want to write it */
  565.     tpp = (struct dttimepack *)&empty.subcode.packs[DTP_RTIME-1];
  566.     tpp->id = DTP_RTIME;
  567.     tcp = &tpp->tc;
  568.     tcp->hhi = tcp->hlo = 0;
  569.     tcp->mhi = tcp->mlo = tcp->shi = tcp->slo = tcp->fhi = tcp->flo = 0xA;
  570.     dtf.subcode.sid.ctrlid = 0;
  571.  
  572.     /* numpacks tells how many packs are written onto the DAT */
  573.     dtf.subcode.sid.numpacks = 2;    /* ATIME is 2, PTIME is 1 */
  574. }
  575.  
  576. main(int argc, char **argv)
  577. {
  578.     CDPLAYER *cd;
  579.     CDSTATUS cdstatus;
  580.     CDPARSER *cdparser;
  581.     CDFRAME buf[NFRAMES];        /* CD input buffer */
  582.     int dat;            /* dat tape fd */
  583.     int status;
  584.     int n = 1;
  585.     int i;
  586.     int excl_id;            /* id as returned by mediad */
  587.     int maj, min;            /* dat firmware rel major&minor # */
  588.  
  589.     if (argc == 2 && !strncmp(argv[1],"-q")) {
  590.     verbose=0;
  591.     }
  592.     else if (argc!=1) {
  593.     fprintf(stderr, "usage: %s [-q]\n",argv[0]);
  594.     exit(-1);
  595.     }
  596.     
  597.     /*
  598.      * open the default CD drive. This will get exclusive access
  599.      * from mediad.
  600.      */
  601.     cd = CDopen(0, "r");
  602.     if (!cd) {
  603.         fprintf(stderr,"Couldn't open CD-ROM drive\n");
  604.         exit(-1);
  605.     }
  606.  
  607.     cdparser = CDcreateparser();
  608.     if (!cdparser) {
  609.         fprintf(stderr,"Couldn't create CD parser\n");
  610.         exit(-1);
  611.     }
  612.  
  613.     /* 
  614.      * add callback functions to deal with events from the CD-ROM 
  615.      * here's why:
  616.      *    a.    we do NOT read ptime from the CD. We
  617.      *        calculate it ourselves, starting from 0 at the beginning
  618.      *        of a program, and incrementing from the start of the first
  619.      *        non-zero index. Thus we have no ptime callback.
  620.      *  b.    we do NOT read atime from the CD. We calculate it 
  621.      *        ourselves. Thus we have no atime callback.
  622.      *    c.    we read the control bits to pass through the copy
  623.      *        prohibit bit. This is legally required. Don't remove it.
  624.      *        (cd_control_func)
  625.      *    d.    we transfer index and program number from CD to DAT.
  626.      *        (cd_index_func, cd_pnum_func)
  627.      *    e.    The cd_audio function transfers the audio data to a queue,
  628.      *        accounting for the difference in frame size between the media.
  629.      */
  630.     CDaddcallback(cdparser, cd_control, (CDCALLBACKFUNC) cd_control_func, 0);
  631.     CDaddcallback(cdparser, cd_index, (CDCALLBACKFUNC)  cd_index_func, 0);
  632.     CDaddcallback(cdparser, cd_pnum, (CDCALLBACKFUNC) cd_pnum_func, 0);
  633.     CDaddcallback(cdparser, cd_audio, (CDCALLBACKFUNC) cd_audio_func, 0);
  634.  
  635.     /*
  636.      * initialize our idea of the state of the CD-ROM
  637.      */
  638.     CDgetstatus(cd, &cdstatus);
  639.  
  640.     /*
  641.      * Make sure everything is kosher with the CD-ROM. Must
  642.      * have an audio disc in before the program is run.
  643.      */
  644.     if (cdstatus.state == CD_NODISC) {
  645.         fprintf(stderr,"No disc in CD-ROM drive\n");
  646.         exit(-1);
  647.     }
  648.     else if (cdstatus.state == CD_CDROM) {
  649.         fprintf(stderr,"Disc in CD-ROM drive is not an audio CD\n");
  650.         exit(-1);
  651.     }
  652.     else if (cdstatus.state == CD_ERROR) {
  653.         fprintf(stderr,"Error reading CD-ROM drive\n");
  654.         exit(-1);
  655.     }
  656.  
  657.     /*
  658.      * Ask mediad for exclusive access to the DAT drive.
  659.      */
  660.     excl_id = mediad_get_exclusiveuse(datdev, "cdtodat");
  661.  
  662.     /*
  663.      * Open the DAT drive
  664.      */
  665.     dat = open(datdev, O_RDWR);
  666.     if (dat < 0) {
  667.         perror("Could not open DAT drive:");
  668.         exit(-1);
  669.     }
  670.  
  671.  
  672.     if (get_firmware_revision(dat, &maj, &min) < 0) {
  673.         fprintf(stderr,"Couldn't get DAT firmware revision\n");
  674.         exit(-1);
  675.     }
  676.     /* pre-2.63 DAT drives don't work with audio */
  677.     if (maj < 2 || (maj == 2 && min < 63)) {
  678.         fprintf(stderr,"DAT firmware rev %d.%d is too old -- you must have 2.63 or greater\n",maj,min);
  679.         exit(-1);
  680.     }
  681.  
  682.     if (prepare_dat(dat) < 0) {
  683.     exit(-1);
  684.     }
  685.  
  686.     sproc(write_DAT,PR_SALL,dat);
  687.     while(n) {
  688.         n = CDreadda(cd, buf, NFRAMES);
  689.  
  690.         if (n < 0) {
  691.             fprintf(stderr,"Error reading CD-ROM drive\n");
  692.             finish = 1;
  693.             exit(-1);
  694.         }
  695.         for (i = 0; i < n; i++) {
  696.             CDparseframe(cdparser, &buf[i]);
  697.         }
  698.     }
  699.  
  700.     finish = 1;
  701.     wait(&status);            /* wait for child to complete */
  702.  
  703.     /* 
  704.      * now finish up the DAT tape with a lead-out section marking
  705.      * EOT
  706.      */
  707.     if (finish_dat(dat) < 0) {
  708.     exit(-1);
  709.     }
  710.  
  711.     if(verbose) printf("DAT tape is complete\n");
  712. }
  713.